/*
 * Robotrader.java
 * Robot que hara un trading automatico en funcion de la triple pantalla de alexander elder algo 
 * modificada
 *
 * Autor: Javier Falces Marin
 * Fecha: 31 enero 2012
 *
 */


//Clases de comunicacion con IB
import com.ib.client.Contract;
import com.ib.client.ContractDetails;
import com.ib.client.EClientSocket;
import com.ib.client.EWrapper;
import com.ib.client.EWrapperMsgGenerator;
import com.ib.client.Execution;
import com.ib.client.Order;
import com.ib.client.OrderState;
import com.ib.client.UnderComp;

//Clases para la interfaz grafica
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

//Otras clases auxiliares
import java.util.Calendar;
import java.text.SimpleDateFormat;
import java.util.Map;
import java.util.TreeMap;
import java.util.Vector;

import java.math.*;


 class Robotrader extends JFrame implements EWrapper {

    //Comunicacion con IB
    EClientSocket   m_client = new EClientSocket(this);
    //Pantalla donde se escriben los mensajes que vienen de Interactive Brokers
    IBTextPanel     m_mensajes = new IBTextPanel("Respuestas de Interactive Brokers", false);

    //Componentes interfaz grafica
    JButton b_conectar = new JButton("Conectar");
    JButton b_tiempoReal = new JButton("Activar precios");
    JTextField t_accion = new JTextField("SELL",10);// or BUY
    JTextField t_ticker = new JTextField("EUR",10);
    JTextField t_moneda = new JTextField("USD",10);
    
    int numcompras=0;
    int numventas=0;
    int hora,minutos,segundos;
   
    
    

    //Ver el metodo nextValidId
    int idActual = 0;
    int [] idacciones=new int [40];
    int contadorid=0;

    /*
     *CERROJOS DE TODO EL PROGRAMA .........................................
     * 
     */
    //Para cambiar el texto y la funcion del boton de conectar
    boolean conectado = false;//cerrojo de conexion/desconexion

    //Para filtrar las actualizaciones de posiciones y de dinero
    
    boolean monitorizandoDinero = false;//cerrojo para ver datos en la cuenta
    boolean monitorizandoPosiciones = false;//Cerrojo para ver posiciones de orden abierta NO USA
    boolean transmitir=true;
    
    //cerrojo ver datos de mercado en tiempo real
    
    boolean reqmarketdata=true;//cerrojo empezar/desactivar visionado precios Tiempo real
    boolean mostrarprecios=false;//cerrojo que solo muestra precios si le doy a ese boton
    boolean espera=true;//cerrojo que pesra a obtener los datos y seguir con el autmata
    
    //Cerrojo automata-triple ventana
    
    
    boolean terminado=false;//STOP bucle en caso de compra /venta
    //Cerrojo comprar/vender al coger datos
    
    boolean comprar=false;//si voy a comprar despues de recoger valores,compra o vende
    
    boolean compraforex=false;//Distingue entre compra o venta para llamar a metodo
    int ncompraforex=0;
    boolean vendeforex=false;//Distingue entre compra o venta para llamar a metodo
    int nvendeforex=0;
    //cerrojo medias
    
    boolean recogiendodatos=false;//distingue medias en el onhistorical data
    int cerrojo=3;//distingue media larga,media y corta
    
    //Cerrojo RSI
    
    boolean recogiendodatos2=false;//distingue rsi en onhistoricaldata
    
    /*
     * .....................................................................
     * 
     */
    
    //Para ir guardando los precios del historico y luego hacer calculos en el automata
    Vector<Double> histoClose = new Vector();

    //Formato de fecha para el metodo onHistorico
    SimpleDateFormat formatoFecha = new SimpleDateFormat("yyyyMMdd HH:mm:ss");

    //Tabla de dos columnas, la primera es el nombre del instrumento y la segunda
    //la ultima posicion.
    Map<String, Integer> posiciones=new TreeMap<String, Integer>();
    double media1;//MEDIA LARGA
    double media2;//MEDIA MEDIA
    double media3;//MEDIA CORTA
    double RSI; //RELATIVE STRENGTH INDICATOR
    double dineroencuenta=0.0;
    
    
    
    
    
    int vueltas=0;//Vueltas que da al array de divisas el automata
    double precioActualBid=0.0;//highest price that a buyer is willing to pay for a good
    double precioActualAsk=0.0;// is the price a seller states she or he will accept for a good, compra

    int seleccion=0; //entero que ira aumentando sobre lo que invertir buscando oportunidades
    
    
    int numerocompras=0;
    int numeroventas=0;
    boolean flag=false;
   
    
    /*
     * DONDE BUSCARA INVERTIR-------------------------------------------------
     */

    
    
    String [] ticker={"EUR","GBP","USD","USD","AUD"};   //Todas las posiblidades FOREX
    String [] exchange={"USD","USD","CHF","CAD","USD"};//currency
     
     
    /*
     * EUR.USD:1,322€,GBP.USD:1.587 GBP,USD.CHF:0.912$,USD.CAD:0.99185$,AUD.USD:1.0479 AUD,EUR.JPY:110.7€
     */

    double [] cantidadmaximacompra={3000000 ,3000000 ,4000000,4000000,3000000};//http://www.interactivebrokers.com/en/trading/exchanges.php?exch=ibfxpro&showcategories=&ib_entity=llc
    double [] cantidadmaximaventa={3000000,3000000,4000000,4000000,3000000};
    /*
     * VALORES PARA MEDIDAS---------------------------------------------------
     * Combinaciones, consultar http://interactivebrokers.com/php/apiUsersGuide/apiguide/api/historical_data_limitations.htm
     */
    
    String [] diasMedias={"1 M","2 W","4 D"};
    String [] barsize={"1 day","1 day","1 hour"};
    String diasRSI="1 D";
    String barsizeRSI="3 mins";
    
    
    /*
     * CONSTANTES
     */
  
    int RSIsoporte=30;//30-40
    int RSIresistencia=70;//70-60 para que haya mas movimientos
    double trailingamount=0.0012;//0.1% del distancia del stop
   
   /*
     * Memoria para cerrar ordenes despues
     */
   boolean intradia=false;//si es true cierra todos los dias ordenes abiertas INTRADIA
   int [] seleccioncompras=new int[99];
   int contseleccioncompras=0;
   int [] seleccionventas=new int[99];
   int contseleccionventas=0; 
    
    /*
     * 
     */
    //Composicion de la interfaz grafica. No es un apartado de interes para los automatas,
    //que pueden funcionar perfectamente en modo texto. Para los principiantes en programacion,
    //se recomienda pulsar el menos a la izquierda de la proxima linea y pasar al siguiente apartado.
    Robotrader() {

            super();

            JPanel autoPanel = new JPanel(new GridBagLayout());
            JPanel otroPanel = new JPanel(new GridLayout(0,1));
            
            
            JButton b_automata = new JButton ("Triple Ventana - Robot(Javier Falces Marin)");

            


            GridBagConstraints labels = new GridBagConstraints();
            GridBagConstraints texto = new GridBagConstraints();
            GridBagConstraints botones = new GridBagConstraints();


            texto.gridwidth=1;
            texto.anchor=GridBagConstraints.NORTHWEST;
            texto.weightx=1.0;
            texto.insets=new Insets(1,1,1,1);
            texto.gridx=2;

            labels = (GridBagConstraints)texto.clone();
            labels.weightx=0.0;
            labels.anchor=GridBagConstraints.EAST;
            labels.gridx=1;

            botones = (GridBagConstraints)labels.clone();
            botones.gridx=0;
           
            otroPanel.add(m_mensajes);
            otroPanel.setPreferredSize(new Dimension(600,250));

            //Asociamos cada boton al metodo que queremos que se ejecute cuando
            //lo pulsamos
            b_conectar.addActionListener( new ActionListener() {
                public void actionPerformed( ActionEvent e) {
                        onConectar();
                }
            });
    

            b_automata.addActionListener( new ActionListener() {
                public void actionPerformed( ActionEvent e) {
                    terminado=false;
                    onAutomata();
               
                
                }
            });
 
                         

           
            getContentPane().add(autoPanel, BorderLayout.NORTH);
            getContentPane().add(otroPanel, BorderLayout.SOUTH);

            setTitle("Robotrader 2012-Tripleventana 3.0");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLocationByPlatform(true);

            m_mensajes.setText("Conexion: puerto 7496 y aceptar peticiones\n"+
                               " Autor:Javier Falces Marin\n"+
                               "Solo trabajara en divisas, FOREX \n"+
                               " Triple Ventana:Comparara por las medias el grafico semanal y si sale opcion de compra o venta pondra una señal\n"
                    + "pasando a la segunda ventana que mirara el grafico diario y sus oscilaciones.\n"
                    + "Colocando una orden de Compra o Venta Trail \n");

            pack();

    }







    //***BOTON CONECTAR***
    //Peticion de conexion
    void onConectar() {
        if(conectado==false){
            //Con la siguiente linea, solicitamos la conexion a IB.
            m_client.eConnect(null,7496,0);
            //Si consigue conectarse...
            if (m_client.isConnected()) {
                //Cambiamos el texto del boton de conectar
                b_conectar.setText("Desconectar");
                conectado=true;
                m_mensajes.add("[MENSAJE] Conectado a las " + m_client.TwsConnectionTime());
                idActual = idActual + 1;
                return;
                }
            }
        if(conectado==true){
            //Solicitamos la desconexion
            m_client.eDisconnect();
            conectado=false;
            //Cambiamos el texto del boton de conectar
            b_conectar.setText("Conectar");
            return;
        }
    }

    //Cada transaccion con el servidor tiene un numero que la identifica. Cuando
    //nos conectamos, el servidor nos comunica la primera Id no utilizada (orderId)
    //llamando a este metodo.
    public void nextValidId(int orderId) {
    	String msg = EWrapperMsgGenerator.nextValidId( orderId);
        //m_mensajes.add("[MENSAJE] " + msg) ;
        idActual = orderId;
    }


    
      //***BOTON COMPRAR/VENDER***
    //Manda una orden de compra o venta al mercado. Si auto=true, la orden viene
    //del automata, si auto=false, la orden viene del boton comprar/vender

    
     void onComprar(String ticker,String moneda) {
        //Definimos primero el instrumento sobre el que vamos a actuar con lo que haya
        //escrito el usuario en el bloque central de la interfaz grafica
        Contract contract = new Contract();
        //onDatosCuenta();//dineroencuenta 

	//contract.m_symbol = t_ticker.getText();
        contract.m_symbol =ticker;
	contract.m_secType = "CASH";
	contract.m_expiry = "";
	contract.m_exchange = "IDEALPRO";
        
	
	//contract.m_currency = t_moneda.getText();
        contract.m_currency =moneda;
        //Con el instrumento definido, indicamos que operacion queremos hacer
        Order orden1 = new Order();

        orden1.m_orderId = idActual;

        //Si la orden es del automata, se ignora si en la interfaz pone BUY o SELL
        orden1.m_action = "BUY";

             
        //orden1.m_orderType = "TRAIL"; // orden a MERCADO(MKT)=> TRAIL,TRAILLIMIT
        orden1.m_orderType = "TRAIL";
        //Maximo posible de acciones permitido
        
        //double dinerogastable=maximoporpuja[seleccion];
        //double cantidad=Math.rint(dinerogastable/precioActualAsk);
        double cantidad=cantidadmaximacompra[seleccion];
         orden1.m_totalQuantity = (int) cantidad;
         
         //Para el error de minimun price variation
        /* if(exchange[seleccion].equals("JPY")){trailingamount=trailingamountJPY;}
         else{trailingamount=trailingamountcopia;}*/
         
         //double trailstopprice=Math.rint(precioActualAsk*(1-trailingamount)*1000)/1000;//donde el limite
         
         double auxprice=trailingamount;//distancia al stop
        
         //orden1.m_trailStopPrice=trailstopprice;//para ordenes limitadas de trail
         orden1.m_auxPrice =auxprice; //precio amount 0.1,si baja 0.1 stop 1%
         //orden1.m_lmtPrice = Math.rint(precioActualAsk*(1-porcentajecompra)*1000)/1000; // precio ordenes LIMIT (si orden1.m_orderType = LMT)
        //orden1.m_lmtPrice =precioActualAsk;//limitoffset distancia de limite a stop
        
         orden1.m_transmit = transmitir;  //PARA VALIDAR
         m_mensajes.add("\n [3ºvent]COMPRA:"+",CANTIDAD:"+ cantidad);
        //Email email= new Email();
        // String [] args={"[Robot]Venta"+ticker[seleccion]+"."+exchange[seleccion],"VENTA:"+precioActualBid+",CANTIDAD:"+cantidad};
        //String [] args={"[Robot]Compra","COMPRA:"+precioActualAsk+",CANTIDAD:"+ cantidad};
         numerocompras++;
        //Con la siguiente linea, solicitamos la operacion a IB.
        
         m_client.placeOrder(orden1.m_orderId,contract,orden1);
        
         idacciones[contadorid]=idActual;//En este array guardo las IDS para cancelarlos todos
         contadorid++;
         //Acabamos de utilizar esta idActual, sumamos 1 para pasar a la siguiente
        idActual = idActual + 1;
        
    
            //automata=false; //Termina el automata
        
               }
   void onVender(String ticker,String moneda){
   //Definimos primero el instrumento sobre el que vamos a actuar con lo que haya
        //escrito el usuario en el bloque central de la interfaz grafica
        Contract contract = new Contract();
        //onDatosCuenta();//dineroencuenta 

	contract.m_symbol =ticker;
	contract.m_secType = "CASH";
	contract.m_expiry = "";
	contract.m_exchange = "IDEALPRO";
        contract.m_currency =moneda;
        //Con el instrumento definido, indicamos que operacion queremos hacer
        Order orden1 = new Order();

        orden1.m_orderId = idActual;
        
        //Si la orden es del automata, se ignora si en la interfaz pone BUY o SELL
        orden1.m_action = "SELL";
        //orden1.m_orderType = "TRAIL"; // orden a MERCADO(MKT)=> TRAIL,TRAILLIMIT
        orden1.m_orderType = "TRAIL";
        //Maximo posible de acciones permitido
        
        //double dinerogastable=maximoporpuja[seleccion];
        //double cantidad=Math.rint(dinerogastable/precioActualBid);//Otra divisa
        double cantidad=cantidadmaximaventa[seleccion];
         orden1.m_totalQuantity = (int) cantidad;
        //orden1.m_trailStopPrice=.5;
         
         /*if(exchange[seleccion].equals("JPY")){trailingamount=trailingamountJPY;}
         else{trailingamount=trailingamountcopia;}*/
         
         //double trailstopprice=Math.rint(precioActualBid*(1+trailingamount)*1000)/1000;//Donde el stop
         double auxprice=trailingamount;//Dsitancia al stop
        
         
        //orden1.m_trailStopPrice=trailstopprice;  //para ordenes limitadas de trail   
        orden1.m_auxPrice =auxprice; //Amount, diferencia de precio de mercado y stoploss
        //orden1.m_lmtPrice = Math.rint(precioActualBid*(1+porcentajecompra)*1000)/1000; // precio ordenes LIMIT (si orden1.m_orderType = LMT)
        //orden1.m_lmtPrice =precioActualBid;
        
        
         orden1.m_transmit = transmitir;  //PARA VALIDAR
        //Con la siguiente linea, solicitamos la operacion a IB.
         m_mensajes.add("\n [3ºvent]VENTA:"+",CANTIDAD:"+cantidad);
         //envia mail si vende
         //Email email= new Email();
        // String [] args={"[Robot]Venta"+ticker[seleccion]+"."+exchange[seleccion],"VENTA:"+precioActualBid+",CANTIDAD:"+cantidad};
        //String [] args={"[Robot]Venta","VENTA:"+precioActualBid+",CANTIDAD:"+cantidad};
         
         //email.main(args);
         numeroventas++;
         
         m_client.placeOrder(orden1.m_orderId,contract,orden1);
        
         idacciones[contadorid]=idActual;//En este array guardo las IDS para cancelarlos todos
         contadorid++;
        //Acabamos de utilizar esta idActual, sumamos 1 para pasar a la siguiente
        idActual = idActual + 1;
       
            //automata=false; //Termina el automata
        
   
   
   
   
   
   }
   /*
    * 
    * Metodo que a partir de una hora me cerrar todas las operaciones abiertas
    */
   void CierraTodo(){
       if(intradia){
           int seleccioncopia=seleccion;//para restablecer valores de antes,que sera 0
           
    for(int i=0; i<contseleccioncompras; i++){//cierra las de compra, vendiendo
        seleccion=seleccioncompras[i];
        onVender(ticker[seleccion],exchange[seleccion]);  
        
                }
    contseleccioncompras=0;
    for(int i=0; i<contseleccionventas; i++){//cierra las de compra, vendiendo
        seleccion=seleccionventas[i];
        onComprar(ticker[seleccion],exchange[seleccion]);  
        
                }
    contseleccionventas=0;     
    
    seleccion=seleccioncopia;
    m_mensajes.add("\n Cierra Todas las operaciones a diario antes de las 5:00 pm");
       }
    }
   void TerceraVentana(){
   /* reqmarketdata=false;
    onReqMarketData();//Desconecta*/
    
                
        if(compraforex && !vendeforex){
            m_mensajes.add("Mandando email de compra...");
            Email email= new Email();
            email.compra(seleccion);
            onComprar(ticker[seleccion],exchange[seleccion]);
            
            seleccioncompras[contseleccioncompras]=seleccion;//almacena que selecciones hay para mandar la operacion contraria
            contseleccioncompras++;
            
            seleccion++;
            return;
             }
        if(!compraforex && vendeforex){ 
            m_mensajes.add("Mandando email de venta...");
             Email email= new Email();
             email.vende(seleccion);
             onVender(ticker[seleccion],exchange[seleccion]);
             
            seleccionventas[contseleccionventas]=seleccion;//almacena que selecciones hay para mandar la operacion contraria
            contseleccionventas++;
            
             
             seleccion++;
             return;
             }
        
                        
    }
    


      //Informacion sobre si la orden se ha ejecutado o no, y a que precios
      //Lo llama el servidor cuando dispone de informacion nueva
     public void orderStatus( int orderId, String status, int filled, int remaining,
    						 double avgFillPrice, int permId, int parentId,
    						 double lastFillPrice, int clientId, String whyHeld) {
        // received order status
    	String msg = EWrapperMsgGenerator.orderStatus( orderId, status, filled, remaining,
    	        avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld);
        
       // m_mensajes.add("[ORDEN] " +  msg);
        
        
        
        
    }
     


     //Estos dos metodos son llamados por el servidor para informar sobre ordenes
     //abiertas, esto es, que no han sido completamente ejecutadas
    public void openOrder( int orderId, Contract contract, Order order, OrderState orderState) {
        // received open order
    	String msg = EWrapperMsgGenerator.openOrder( orderId, contract, order, orderState);
      //  m_mensajes.add("[ORDEN] " + msg) ;
    }

    public void openOrderEnd() {
        // received open order end
    	String msg = EWrapperMsgGenerator.openOrderEnd();
     //   m_mensajes.add("[ORDEN] " + msg) ;
    }

    //Estos dos metodos son llamados por el servidor para informar sobre la
    //ejecucion de las ordenes que hemos enviado
    public void execDetails(int reqId, Contract contract, Execution execution)
    {
    	String msg = EWrapperMsgGenerator.execDetails(reqId, contract, execution);
    //	m_mensajes.add("[ORDEN] " + msg);
    }

    public void execDetailsEnd(int reqId)
    {
    	String msg = EWrapperMsgGenerator.execDetailsEnd(reqId);
    //	m_mensajes.add("[ORDEN] " + msg);
    }

    /**
 * Pide informaci�n de un determinado ticker en tiempo real. En el String ticklist se 
 * configura el tipo de informaci�n que queremos recibir. En caso de desear dejar de 
 * recibir la informaci�n en tiempo real hay otro m�todo que lo permite. 
 */
    
    
	void onReqMarketData(){
if(!reqmarketdata){
    reqmarketdata=true;
    m_client.cancelMktData(idActual-1);
    b_tiempoReal.setText("Activar precios");
    //if(automata){m_mensajes.add("Automata en la desconecxion a TRUE ");}
    return;
    }
            
if(reqmarketdata){
		
	Contract contract = new Contract();


            contract.m_symbol=ticker[seleccion];//Si estoy en el automata coge de la lista
            contract.m_currency=exchange[seleccion];
                      
            

	contract.m_secType = "CASH";
	contract.m_expiry = "";
	contract.m_exchange = "IDEALPRO";

		String ticklist = "100,101,104,105,106,107,165,221,225,233,236,258";
                
                
		m_client.reqMktData(idActual,contract,ticklist,false ); // si se pone el snapshot a true no hace falta el ticklist
                b_tiempoReal.setText("Desactivar precios");
                idActual = idActual + 1;
           
        }

        }   
	
        
        
        /*
         * Saca el precio de las acciones, aqui dentro automata se pone a FALSE
         */
        public void tickPrice( int orderId, int field, double price, int canAutoExecute) {
            
            //if(!terminado |seleccion==13 |seleccion==18){automata=true;}//chapuza para solucionar automata
 
            if (ncompraforex==1) {compraforex=true;}
            if(nvendeforex==1) {vendeforex=true;}
            boolean espera=true;
            if(espera){
                if(field==1){//precio dmaximo que ofrece un comprador, osea para vender nosotros
			
                        String msg = EWrapperMsgGenerator.tickPrice( orderId, field, price, canAutoExecute);
                        precioActualBid=price;//highest price that a buyer is willing to pay for a good
                      if(mostrarprecios ){ m_mensajes.add("\n[PrecioVenta] " +  precioActualBid);}
                      reqmarketdata=false;
                      
                              }
		if(field==2){
			
                        String msg = EWrapperMsgGenerator.tickPrice( orderId, field, price, canAutoExecute);
                        precioActualAsk=price;// is the price a seller states she or he will accept for a good
                        if(mostrarprecios ){m_mensajes.add("\n[PrecioCompra] " +  precioActualAsk);}
                        reqmarketdata=false;
                        espera=false;
                        
		               }
            }
            if(comprar && !espera){TerceraVentana();}
        }
                

        

    //***BOTON DATOS HISTOICOS***
    //Peticion de un historico de las ultimas dos semanas en barras de 15 minutos
    //Lo hare con 1M-1D
    //Lo hare con 2W-1D
    //Lo hare 2D-1H
    void onHistorico(String duration, String barSize) {
        //Definimos primero el instrumento sobre el que vamos a actuar con lo que haya
        //escrito el usuario en el bloque central de la interfaz grafica
        Contract contract = new Contract();

	
	contract.m_secType = "CASH";
	contract.m_expiry = "";
	contract.m_exchange = "IDEALPRO";
        contract.m_symbol=ticker[seleccion];//Si estoy en el automata coge de la lista
        contract.m_currency=exchange[seleccion];
                      
            

        //Con el instumento definido, configuramos el resto de las opciones
        //En Forex se utiliza MIDPOINT
        String whatToShow = "TRADES";
        whatToShow = "MIDPOINT";

        //Para Stock (acciones) es recomendable poner UseRTH a true
        int soloHorasAperturaOficial = 0;


        //Date es la fecha del ultimo dato (el mas reciente) que recibiremos.
        //En este ejemplo seran el dia y la hora actuales.
        Calendar ahora = Calendar.getInstance();
        String date = formatoFecha.format(ahora.getTime());
        
        //Duration indica cuanto tiempo abarca el historico que recibimos y barSize
        //la duracion de la barra. No todas las combinaciones de estos dos parametros
        //son posibles, consultar http://interactivebrokers.com/php/apiUsersGuide/apiguide/api/historical_data_limitations.htm
       // String duration = "1 M";
        //String barSize = "1 D";*/

        //Con la siguiente linea, solicitamos el historico a IB.
        histoClose.clear();//borro antes de pedir nuevos datos
        m_client.reqHistoricalData(idActual,contract,date,duration,barSize,whatToShow,soloHorasAperturaOficial,1 );
        //Acabamos de utilizar esta idActual, sumamos 1 para pasar a la siguiente
        idActual = idActual + 1;
        
    }

    //Respuesta del servidor a la peticion de historico
    // (cada barra nueva = una llamada a este metodo)

   
    public void historicalData(int reqId, String date, double open, double high, double low,
                               double close, int volume, int count, double WAP, boolean hasGaps) {
        
        String msg = EWrapperMsgGenerator.historicalData(reqId, date, open, high, low, close, volume, count, WAP, hasGaps);
    	if(!recogiendodatos2 && !recogiendodatos){//no quiero que me salga en los automatas
        m_mensajes.add("[DATO] " + msg );}
        
     if(recogiendodatos){ 
            //Comprobamos si es la "barra" que informa de que ya hemos recibido todo el historico
            String[] date2 = date.split("-");
            if(date2[0].equals("finished")==true){
                   //Ya tenemos todo el historico, podemos hacer los calculos
                   MediaSegundaParte();
                   
                   return;//No quiero que se repita
                    }
            //Si hemos llegado hasta aqui, es un nuevo dato que no teniamos, lo añadimos
            histoClose.add(close);
     }
     
          if(recogiendodatos2){ 
            //Comprobamos si es la "barra" que informa de que ya hemos recibido todo el historico
            String[] date2 = date.split("-");
            if(date2[0].equals("finished")==true){
                   //Ya tenemos todo el historico, podemos hacer los calculos
                   RSISegundaParte();
                   
                   return;//No quiero que se repita
                    }
            //Si hemos llegado hasta aqui, es un nuevo dato que no teniamos, lo añadimos
            histoClose.add(close);
 }
         
    

    }

/*
 * Para la primera ventana,Sigue la tendencia con medias moviles
 * http://es.wikipedia.org/wiki/Media_m%C3%B3vil
 */
void onMedia(){
    
    recogiendodatos2=false;
    recogiendodatos = true;//booleano que me permite acceder a la segunda parte del historico,medias
    m_mensajes.add("Almacenando el historico para medias...");
    histoClose.clear();
    media1=0.0; //inicializo a cero
    media2=0.0;
    media3=0.0;
    cerrojo=3;
    onHistorico(diasMedias[0],barsize[0]); 
    histoClose.clear();
    
   
    onHistorico(diasMedias[1],barsize[1]); 
    histoClose.clear();
    
    
    onHistorico(diasMedias[2],barsize[2]);
    histoClose.clear();
}
void MediaSegundaParte(){

  if(cerrojo==1){
        int elementos = histoClose.size();
        for(int i=0; i<elementos; i++){
            //Primero sumamos los precios del historico
            media3=media3+histoClose.elementAt(i);
        }
        //Y luego dividimos por el numero de elementos
        media3=media3/elementos;
        m_mensajes.add("\n[MEDIA CORTA] : "+ media3);
    recogiendodatos=false;
    onRSI();//Si es el automata una vez cogidos los datos pasa a segunda ventana
        } 
  if(cerrojo==2){
        int elementos = histoClose.size();
        for(int i=0; i<elementos; i++){
            //Primero sumamos los precios del historico
            media2=media2+histoClose.elementAt(i);
        }
        //Y luego dividimos por el numero de elementos
        media2=media2/elementos;
        m_mensajes.add("\n[MEDIA INTERMEDIA]: " + media2);
    cerrojo=1;
        }
   if(cerrojo==3){
        int elementos = histoClose.size();
        for(int i=0; i<elementos; i++){
            //Primero sumamos los precios del historico
            media1=media1+histoClose.elementAt(i);
        }
        //Y luego dividimos por el numero de elementos
        media1=media1/elementos;
        m_mensajes.add("\n[MEDIA LARGA]: " + media1);
        cerrojo=2;
        }
    }
/*
 * Para la segunda ventana,oscilador indice relativo fuerza
 * http://es.wikipedia.org/wiki/%C3%8Dndice_RSI
 */
void onRSI(){
    recogiendodatos=false;
    cerrojo=0;              //Para evitar resquicios de la primera ventana
    recogiendodatos2=true;
    RSI=0;
    
    m_mensajes.add("Almacenando el historico para RSI...");
    histoClose.clear();
    onHistorico(diasRSI,barsizeRSI);
    
    }
void RSISegundaParte(){
    int elementos = histoClose.size();
    double U[] = new double[900];
    double D[] = new double[900];
    double ucontador,usuma,umedia;
    double dcontador,dsuma,dmedia;
    ucontador=usuma=umedia=dcontador=dsuma=dmedia=0.0;
    double RS=0.0;
    for(int i=0; i<elementos-1; i++){
        U[i]=histoClose.elementAt(i+1)-histoClose.elementAt(i);
        if(U[i]>0){ucontador++;usuma=usuma+U[i];}
        D[i]=histoClose.elementAt(i)-histoClose.elementAt(i+1);
        if(D[i]>0){dcontador++;dsuma=dsuma+D[i];}
         }
    
    
        umedia=usuma/ucontador;
        dmedia=dsuma/dcontador;
        
        if(dcontador==0){dmedia=0.0;}//En caso de tendencias puras
        if(ucontador==0){umedia=0.0;}

    //Si toda la tendencia ascendente ,dmedia sera 0,RSI sera alto
    //Si toda la tendencia descendente ,umedia sera 0, RSI sera bajo
    RS=umedia/dmedia;
    RSI=100-(100/(1+RS));
    if(dmedia==0){RSI=100;} //Toda la tendencia ascendente
    if(umedia==0){RSI=0;} //Toda la tendencia descendente
    m_mensajes.add("\n[RSI]: " + RSI);
    if(RSI==100){m_mensajes.add("-Ascendente pura");}
    if(RSI==0){m_mensajes.add("-Descendente pura");}
    recogiendodatos2=false;
    automataSegundaParte();

}


 
    //***BOTON DINERO CUENTA***
    //Peticion para recibir actualizaciones sobre el estado de la cuenta
    void onDatosCuenta(){
        //Con la siguiente linea, solicitamos la informacion de la cuenta en tiempo real a IB.
        flag=true;
        m_client.reqAccountUpdates(true, "");
        monitorizandoDinero = true;
        
        
        
    }

    //Respuesta del servidor a la peticion de actualizaciones de la cuenta
    // (cada dato nuevo = una llamada a este metodo)
    // Aqui solo imprimimos los CashBalance y el margen, pero IB proporciona
    // decenas de parametros sobre nuestra cuenta. Para verlos todos, descomentar
    // las ultimas lineas
    public void updateAccountValue(String key, String value, String currency,
			String accountName) {
        if(monitorizandoDinero==true && flag){
            if(( key.equals("TotalCashBalance")) && currency.equals("BASE")){
               
                 m_mensajes.add("\n[DINERO] : " + value);
                flag=false;
                
            }
           
        }



    }


    //***BOTON POSICIONES***
    //Peticion para recibir actualizaciones sobre las posiciones (es el mismo que
    //onDatosCuenta())
    void onPosiciones(){
        //Con la siguiente linea, solicitamos la informacion de la cuenta en tiempo real a IB.
        m_client.reqAccountUpdates(true, "");
        monitorizandoPosiciones = false;
    }
    
    //Respuesta del servidor a la peticion de actualizaciones de la cuenta
    // (cada dato nuevo = una llamada a este metodo)
    public void updatePortfolio(Contract contract, int position, double marketPrice,
        double marketValue, double averageCost, double unrealizedPNL, double realizedPNL,
        String accountName) {

        if(monitorizandoPosiciones==true) actualizaPosiciones(contract, position);

    }

    //Actualiza la tabla de posiciones y genera un mensaje si ha habido un cambio
    void actualizaPosiciones(Contract contrato, int posicion){
        String instrumento = contrato.m_symbol +"."+ contrato.m_currency;

        //Genera un mensaje si ha habido un cambio en las posiciones
        if(posiciones.containsKey(instrumento)==false) m_mensajes.add("[POSI] " + instrumento + " - " + posicion);
        else{
            if(posiciones.get(instrumento)!=posicion) m_mensajes.add("[POSI] " + instrumento + " - " + posicion);
        }

        //Actualiza la tabla de posiciones
        posiciones.put(instrumento,posicion);
    }


    //***BOTON AUTOMATA***
    //Ejemplo de como utilizar los metodos de la API en un automata
    //Calcula la media y la mediana del instrumento a partir del historico.
    //Si la media >= mediana => compra
    //Si la media < mediana => vende
    void onAutomata() {
       if(!terminado){ 
        if(seleccion>ticker.length-1){
            seleccion=0;vueltas++;terminado=true; 
            m_mensajes.add("\n-- ESPERA 10 MIN-- \n[VUELTAS]:"+vueltas);
            
                        //gestion tiempo
            Calendar calendario = Calendar.getInstance();
            hora =calendario.get(Calendar.HOUR_OF_DAY);
            minutos = calendario.get(Calendar.MINUTE);
            segundos = calendario.get(Calendar.SECOND);
            m_mensajes.add("\n[HORA]:"+hora + ":" + minutos + ":" + segundos);
            
            m_mensajes.add("\n[NUM.COMPRAS]:"+numerocompras);
            m_mensajes.add("\n[NUM.VENTAS]:"+numeroventas);
            onDatosCuenta();//dinero total

            //gestion reconexion cada 10 minutos
            if (m_client.isConnected()==false){m_client.eConnect(null,7496,0);}

            //gestion tiempo

            
            if(hora==16 && minutos>45 && minutos<55){ CierraTodo();}// en pruebas
            
            
            
            return;
        }//Cuando da la vuelta para
        
        m_mensajes.add("\n Analizare "+ticker[seleccion]+"."+exchange[seleccion]);

        histoClose.clear();
        
        onMedia();}
    
    }
    //Cuando historicalData dice que podemos seguir...
    void automataSegundaParte(){
        
        if(media3>media2 && media3>media1){
            m_mensajes.add("\n [1ºVent]ASCENDENTE");
            if(RSI<RSIsoporte){
                m_mensajes.add("\n [2ºvent]SOPORTE=> COMPRA");
                 //TERCERA VENTANA
                reqmarketdata=true;//para empezar conectado la adquision
                comprar=true;//activa y desactiva la adquisicion precios
                
                mostrarprecios=false;
                
                compraforex=true;
                vendeforex=false;
                
                TerceraVentana();
                  
                
                
                terminado=true;// que siga aunque compre
                return;
                
                }
            m_mensajes.add("\n No cumple 2º vent");
            seleccion++;//Probara otro valor
            onAutomata();
                      
            return;
            }
        if(media3>media2 && media3<media1){
            m_mensajes.add("\n No cumple 1º vent");
            seleccion++;//Probara otro valor
            onAutomata();//Sino me vale busco otro indicador
            return;}
            

        if(media3<media2 && media3>media1){
            m_mensajes.add("\n No cumple 1ºvent");
            seleccion++;//Probara otro valor
            onAutomata();
            return;
            
            }
        if(media3<media2 &&media3<media1){
            m_mensajes.add("\n [1ºVent]DESCENDENTE");
            if(RSI>RSIresistencia){
                m_mensajes.add("\n [2ºVent]RESISTENCIA =>VENDE");
                
                //////TERCERA VENTANA
                reqmarketdata=true;//para empezar conectado la adquision
                comprar=true;//activa y desactiva la adquisicion precios
                mostrarprecios=false;
                
                compraforex=false;
                vendeforex=true;
                
                
                TerceraVentana();
                
                terminado=true;// que siga aunque compre
                return;
                }
            m_mensajes.add("\n No cumple 2º vent");
            seleccion++;//Probara otro valor
            onAutomata();
            return;
            }
        
}


    //Informacion sobre problemas y errores
    public void error(Exception ex) {
            String msg = EWrapperMsgGenerator.error(ex);
            Main.inform( this, msg);
    }

    public void error( String str) {
    	String msg = EWrapperMsgGenerator.error(str);
       // m_mensajes.add("[ERROR/INFO] " + msg);
    }

    public void error( int id, int errorCode, String errorMsg) {
        // received error
    	String msg = EWrapperMsgGenerator.error(id, errorCode, errorMsg);
       // m_mensajes.add("[ERROR/INFO] " + msg);
    }

    public void connectionClosed() {
        String msg = EWrapperMsgGenerator.connectionClosed();
        Main.inform( this, msg);
    }

    //No utilizamos estas funciones del API en este ejemplo
  //  public void tickPrice( int tickerId, int field, double price, int canAutoExecute) {}
    public void tickOptionComputation( int tickerId, int field, double impliedVol, double delta, double modelPrice, double pvDividend) {}
    public void tickSize( int tickerId, int field, int size) {}
    public void tickGeneric( int tickerId, int tickType, double value) {}
    public void tickString( int tickerId, int tickType, String value) {} 
    public void tickSnapshotEnd(int tickerId) {}    
    public void tickEFP(int tickerId, int tickType, double basisPoints, String formattedBasisPoints,
    					double impliedFuture, int holdDays, String futureExpiry, double dividendImpact,
    					double dividendsToExpiry) {} 
    public void contractDetails(int reqId, ContractDetails contractDetails) {}
    public void contractDetailsEnd(int reqId) {}
    public void scannerData(int reqId, int rank, ContractDetails contractDetails,
                            String distance, String benchmark, String projection, String legsStr) {}
    public void scannerDataEnd(int reqId) {}
    public void bondContractDetails(int reqId, ContractDetails contractDetails) {}
    public void updateMktDepth( int tickerId, int position, int operation,
                    int side, double price, int size) {}
    public void updateMktDepthL2( int tickerId, int position, String marketMaker,
                    int operation, int side, double price, int size) {}
    public void updateAccountTime(String timeStamp) {}    
    public void accountDownloadEnd(String accountName) {}
    public void updateNewsBulletin( int msgId, int msgType, String message, String origExchange) {}
    public void managedAccounts( String accountsList) {}
    public void scannerParameters(String xml) {}
    public void currentTime(long time) {}
    public void fundamentalData(int reqId, String data) {}
    public void deltaNeutralValidation(int reqId, UnderComp underComp) {}
    void displayXML(String title, String xml) {}
    public void receiveFA(int faDataType, String xml) {}
    private void copyExtendedOrderDetails( Order destOrder, Order srcOrder) {}
    public void tickOptionComputation(int tickerId, int field, double impliedVol, double delta, double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice) {
        throw new UnsupportedOperationException("Not supported yet.");
        
    }
       //***BOTON DATOS EN TIEMPO REAL***
    //Peticion de barras en tiempo real (una cada 5 segundos)
    void onTiempoReal() { }

    //Respuesta del servidor a la peticion de barras en tiempo real
    // (cada barra nueva = una llamada a este metodo)
    public void realtimeBar() {  }

    @Override
    public void realtimeBar(int reqId, long time, double open, double high, double low, double close, long volume, double wap, int count) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

}
